using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using UDS.Management.Data.Package;
using System.Xml.Schema;
using System.Reflection;
using System.Xml.Serialization;
using UDS.Management.Data;

namespace UDS.Management.Data.Package
{
    /// <summary>
    /// Loads, validates, and serializes the XML SQL Jobs file from disk or from the specified assembly
    /// </summary>
    internal class SQLJobXMLHelper
    {
        private XmlReaderSettings readerSettings = null;
        private Stream XsdStream = null;

        public SQLJobXMLHelper()
        {
            XsdStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(SCHEMA_SQLJOBS_NAME);
            using (XmlTextReader replXsdReader = new XmlTextReader(XsdStream))
            {
                readerSettings = new XmlReaderSettings();
                readerSettings.ValidationType = ValidationType.Schema;
                readerSettings.Schemas.ValidationEventHandler += new ValidationEventHandler(ReaderSettings_ValidationEventHandler);
                readerSettings.ValidationEventHandler += new ValidationEventHandler(ReaderSettings_ValidationEventHandler);
                readerSettings.Schemas.Add("http://www.sosceo.com/server/Install/SQLJobsSchema", replXsdReader);
                replXsdReader.Close();
            }
        }


        /// <summary>
        /// The name of the replication xsd file in the assembly
        /// </summary>
        private const string SCHEMA_SQLJOBS_NAME = "UDS.Management.Data.SQLJobsSchema.xsd";

        /// <summary>
        /// Load the DB Replication definition file from the assembly loader
        /// </summary>
        /// <exception cref="Exceptions.PackageValidationException">A PackageValidationException is thrown if the manifest does not match the schema</exception>
        /// <param name="replicationDefinitionStream">The manifest stream to validate</param>
        /// <returns>A database manifest object</returns>
        internal SQLJobDefinition Load(ScriptSource source)
        {
            // Now serialize the manifest
            using (XmlReader ValidatingReader = XmlTextReader.Create(source.Stream, readerSettings))
            {
                try
                {
                    // Deserialize the stream
                    XmlSerializer Serializer = new XmlSerializer(typeof(SQLJobDefinition));

                    return (SQLJobDefinition)Serializer.Deserialize(ValidatingReader);
                }
                catch (InvalidOperationException ioEx)
                {
                    // Treat the package validation exception specifically so callers
                    // can differentiate between this and an unhandled exception
                    if (ioEx.InnerException is Exceptions.SQLJobValidationException)
                    {
                        Exceptions.SQLJobValidationException SQLJobEx = ioEx.InnerException as Exceptions.SQLJobValidationException;
                        SQLJobEx.PackageName = source.Name;
                        throw SQLJobEx;
                    }
                    else
                    {
                        throw;
                    }
                }
            }
        }

        private void ReaderSettings_ValidationEventHandler(object sender, ValidationEventArgs e)
        {
            if (e.Severity == XmlSeverityType.Error)
            {
                string Message = e.Message.TrimEnd('.');
                Exceptions.SQLJobValidationException ex = new Exceptions.SQLJobValidationException(String.Format("{0} at line {1}, position {2}.", Message, e.Exception.LineNumber, e.Exception.LinePosition));
                throw ex;
            }
        }
    }
}
